D:\a\cssh-rs\cssh-rs\xtask\src\cross_build\strategy\windows_msvc.rs
Line | Count | Source |
1 | | //! Windows-MSVC build orchestration. |
2 | | //! |
3 | | //! On Windows hosts, dispatches to native `cargo build`. On Linux and |
4 | | //! macOS hosts, delegates to [`cargo-xwin`], which fetches the MSVC |
5 | | //! CRT and Windows SDK on first use under the Microsoft Software |
6 | | //! License Terms; this xtask sets `XWIN_ACCEPT_LICENSE=1` on the |
7 | | //! cargo-xwin subprocess only after printing a notice. |
8 | | //! |
9 | | //! [`cargo-xwin`]: https://github.com/rust-cross/cargo-xwin |
10 | | |
11 | | use anyhow::{bail, Result}; |
12 | | |
13 | | use super::super::ensure_rust_target_installed; |
14 | | use super::super::system::windows_msvc::WindowsMsvcSystem; |
15 | | use super::super::system::CrossBuildSystem; |
16 | | |
17 | | pub const TRIPLE: &str = "x86_64-pc-windows-msvc"; |
18 | | |
19 | | /// Build cssh-rs for `x86_64-pc-windows-msvc`. |
20 | | /// |
21 | | /// # Arguments |
22 | | /// * `system` - Injected I/O provider. |
23 | | /// * `release` - When true, build with `--release`; otherwise debug. |
24 | | /// |
25 | | /// # Errors |
26 | | /// Returns an error if the host is not supported, a prerequisite |
27 | | /// install fails, or the build subprocess fails. |
28 | 10 | pub fn build<S: WindowsMsvcSystem>(system: &S, release: bool) -> Result<()> { |
29 | 10 | let host = system.host_os(); |
30 | | // Decide up front whether this (host, target) pair is supported |
31 | | // so we do not run a network-touching `rustup target add` against |
32 | | // a host we cannot finish the build on anyway. |
33 | 10 | let path9 = match host { |
34 | 10 | "windows" => BuildPath::Native3 , |
35 | 7 | "linux" | "macos"2 => BuildPath::CargoXwin6 , |
36 | 1 | _ => bail!("cross-build {TRIPLE} from {host} host is not supported by this xtask yet"), |
37 | | }; |
38 | 9 | ensure_rust_target_installed(system, TRIPLE)?0 ; |
39 | 9 | match path { |
40 | 3 | BuildPath::Native => build_native(system, release), |
41 | 6 | BuildPath::CargoXwin => build_via_xwin(system, host, release), |
42 | | } |
43 | 10 | } |
44 | | |
45 | | enum BuildPath { |
46 | | Native, |
47 | | CargoXwin, |
48 | | } |
49 | | |
50 | 3 | fn build_native<S: WindowsMsvcSystem>(system: &S, release: bool) -> Result<()> { |
51 | 3 | log::info!( |
52 | | "Running `cargo build {}--target {TRIPLE}`", |
53 | 0 | if release { "--release " } else { "" } |
54 | | ); |
55 | 3 | system.run_cargo_build(TRIPLE, release) |
56 | 3 | } |
57 | | |
58 | 6 | fn build_via_xwin<S: WindowsMsvcSystem>(system: &S, host: &str, release: bool) -> Result<()> { |
59 | 6 | ensure_llvm_tooling_available(system, host)?1 ; |
60 | 5 | ensure_cargo_xwin_installed(system)?0 ; |
61 | 5 | log::info!( |
62 | | "Invoking cargo-xwin with XWIN_ACCEPT_LICENSE=1 to accept the \ |
63 | | Microsoft Software License Terms for the MSVC CRT and Windows SDK. \ |
64 | | cargo-xwin downloads them into your local cache on first use; \ |
65 | | nothing is checked into this repository." |
66 | | ); |
67 | 5 | log::info!( |
68 | | "Running `cargo xwin build {}--target {TRIPLE}`", |
69 | 0 | if release { "--release " } else { "" } |
70 | | ); |
71 | 5 | system.run_cargo_xwin_build(TRIPLE, release) |
72 | 6 | } |
73 | | |
74 | | /// Verify that the LLVM tools cargo-xwin and embed-resource need are |
75 | | /// available; do not auto-install (the package manager needs sudo / |
76 | | /// admin, which the xtask must not silently assume). |
77 | 6 | fn ensure_llvm_tooling_available<S: CrossBuildSystem>(system: &S, host: &str) -> Result<()> { |
78 | | // `llvm-rc` is the load-bearing one: `embed-resource` invokes it |
79 | | // to compile the Windows .rc file. `clang` and `lld-link` are |
80 | | // exercised by cargo-xwin's compile/link stages. |
81 | 6 | let missing: Vec<&str> = ["llvm-rc", "clang", "lld-link"] |
82 | 6 | .into_iter() |
83 | 18 | .filter6 (|tool| !system.is_executable_in_path(tool)) |
84 | 6 | .collect(); |
85 | 6 | if missing.is_empty() { |
86 | 5 | log::info!("LLVM tooling (llvm-rc, clang, lld-link) found in PATH"); |
87 | 5 | return Ok(()); |
88 | 1 | } |
89 | 1 | let hint = match host { |
90 | 1 | "linux" => concat!( |
91 | | "install via your distro's package manager, for example ", |
92 | | "`sudo apt install clang llvm lld` on Debian/Ubuntu or ", |
93 | | "`sudo dnf install clang llvm lld` on Fedora", |
94 | | ), |
95 | 0 | "macos" => concat!( |
96 | | "install via Homebrew: `brew install llvm` and ensure its ", |
97 | | "`bin/` directory is on PATH", |
98 | | ), |
99 | 0 | _ => concat!( |
100 | | "install LLVM 14+ via your OS package manager and ensure ", |
101 | | "llvm-rc, clang, and lld-link are on PATH", |
102 | | ), |
103 | | }; |
104 | 1 | bail!( |
105 | | "cargo-xwin needs LLVM tooling that is not in PATH: {}. {hint}.", |
106 | 1 | missing.join(", ") |
107 | | ); |
108 | 6 | } |
109 | | |
110 | 5 | fn ensure_cargo_xwin_installed<S: WindowsMsvcSystem>(system: &S) -> Result<()> { |
111 | 5 | let listed = system.list_cargo_subcommands()?0 ; |
112 | | // `cargo --list` formats each external command as |
113 | | // ` <name> <description>` on its own line. |
114 | 5 | let has_xwin = listed |
115 | 5 | .lines() |
116 | 12 | .any5 (|line| line.split_whitespace().next() == Some("xwin")); |
117 | 5 | if has_xwin { |
118 | 4 | log::info!("cargo-xwin already installed"); |
119 | | } else { |
120 | 1 | let version = system.read_cargo_xwin_version()?0 ; |
121 | 1 | log::info!("Installing cargo-xwin {version}"); |
122 | 1 | system.install_cargo_subcommand("cargo-xwin", &version)?0 ; |
123 | | } |
124 | 5 | Ok(()) |
125 | 5 | } |